perm filename PLISP[L70,TES] blob
sn#009936 filedate 1972-06-27 generic text, type T, neo UTF8
00100 THE LISP70 PATTERN MATCHER
00200
00300 SOURCE
00400 The list (or file or string or list&file) that is scanned by the
00500 pattern matcher. It is a DYNAMIC PUBLIC STREAM VARIABLE.
00600
00700 (BIND SOURCE X1 ... XN)
00800 Pushes down the old SOURCE and replaces it by ⊂X1...XN⊃.
00900
01000 (UNBIND SOURCE X1 ... XN)
01100 Fails unless SOURCE = ⊂X1 ... XN⊃. If
01200 it succeeds, then it restores the former binding of SOURCE.
01300
01400 (TOKEN)
01500 Removes and returns the first token from SOURCE. (Fails if ATOM SOURCE).
01600
01700 (TOKENS M)
01800 Removes and returns a STREAM of the first M tokens from SOURCE.
01900
02000 (POP F X1...XN)
02100 If F is a function of N+M arguments (M>0), this is equivalent to:
02200 (F X1 ... XN (TOKENS M))
02300 Example:
02400 (POP STORE X)
02500 This pops the first token off SOURCE into X.
02600
02700 (MATCH F X1...XN)
02800 Same as POP, but if the result is NIL, then MATCH fails. Example:
02900 (MATCH EQ (QUOTE A))
03000 This removes the first token and fails if it is not A.
03100
03200 (PARSE F X1...XN)
03300 Same as POP, but the result of F is prefixed to SOURCE. Example:
03400 (PARSE SUBST)
03500 This replaces the first two tokens by SUBST(first token, second token).
03600
03700 (LONGEST)
03800 choose(tokens(length(source)), ... , tokens(0))
03900
04000 (SHORTEST)
04100 choose(tokens(0), ... , tokens(length(source)))
04200
04300 (POP M TOKENS F X1...XN)
04400 Specifies M for an F that has a variable number of arguments.
04500
04600 (POP LONGEST F X1...XN)
04700 Tries M=LENGTH(SOURCE) by -1 to 0.
04800
04900 (POP SHORTEST F X1...XN)
05000 Tries M=0 by 1 to LENGTH(SOURCE).
05100
05200 (MATCH M TOKENS GREATERP), (PARSE LONGEST EXPRESSION), (POP SHORTEST LIST)
00100 (REWRITE <dec> <rec> <list>)
00200 Decomposes <list> according to <dec>.
00300 If successful, return <rec>.
00400 If unsuccessful, fail.
00500
00600 Extendable functions have no private variables of their own. Every
00700 colon variable in a <dec> or <rec> is private in its REWRITE. In
00800 Unextendable functions, colon variables are accessed free from the
00900 rewrite.
01000
01100 :X In Extendable Function Otherwise
01200 first: (POP SETC X) (POP SETQ X)
01300 then: (MATCH EQUAL X) (MATCH EQUAL X)
01400 $X (MATCH EQUAL X)
01500 %X first time: (POP BIND PUBLIC CONTEXTUAL X) then: (MATCH EQUAL X)
01600
01700 (POP LAMBDA (X Y) (FOO Y X)) is like Hewitt's KAPPA.
01800 But we have a choice of POP, MATCH, or PARSE.
01900
02000 (DECOMPOSE <dec> <list>)
02100 Decomposes <list> according to <dec>.
02200 If successful, returns T.
02300 If unsuccessful, returns NIL.
02400
02500 [OPT <dec>] = [ALT <dec>|]
02600 [REP <dec>] = [ALT <>|<dec>|<dec><dec>|...]
02700 [STAR <dec>] = [ALT <dec>...<dec>|...|<dec><dec>|<dec>|<>]
02800 [ALT :X | :Y | :Z] sets X, Y, and Z no matter which ALT is selected.
02900 [ALTNUM :N <dec1>|<dec2>|...] sets :N to the no. of the alternative chosen.
03000 The unselected ones are set to ⊂⊃. :N is set to the case no. that worked.
03100
03200 (EXTENDABLE <factored rules>)
03300 The body of an extendable function, i.e.,
03400 (DEFPROP FOO (LAMBDA SOURCE (EXTENDABLE ...)) XEXPR)
03500
03600 (DECATOMS (A1 D1) (A2 D2) ...) is a macro that expands to:
03700 (ALT (PROGN (MATCH EQ @A1) D1) (PROGN (MATCH EQ @A2) D2) ... )
03800
03900 (DECOMPOSE (PARSE LONGEST EXPRESSION) FOO)
04000 Finds the leftmost longest expression in FOO and does not change FOO.
04100
04200 (DETACH (PARSE LONGEST EXPRESSION) FOO)
04300 Same as DECOMPOSE but also removes the expression from FOO. What
04400 this does is bind SOURCE to FOO, decompose SOURCE, set FOO to SOURCE, and
04500 unbind SOURCE.
04600
04700 (SOURCETAIL)
04800 Returns SOURCE and empties it. SOURCE may be an atom.
00100 The various parts of a template translate to LISP as shown:
00200
00300 PLISP LISP
00400
00500 DEC → REC (PROG (V1 V2 ...) (DEC) DEC* (REC) REC*)
00600
00700 (x1 ... xn ) (BIND SOURCE (POP STRIP)) x1* ... xn* (UNBIND SOURCE)
00800 /C70 x (BIND SOURCE (POP C70)) x* (UNBIND SOURCE)
00900 { e } (MATCH DECOMPOSE e)
01000 { e } (MATCH EQUAL e) if the value of e could not be a template.
01100 {if b} (REQUIRE b) i.e., if b then () else fail
01200 {do s} (EFFECT s) i.e., s prog2 ()
01300 {x1,...,xn} {x1}* ... {xn}*
01400 ⊂x1 ... xn⊃@f (MATCH f x1*...xn*)
01500 ⊂x1 ... xn⊃ x1* ... xn*
01600 [f x1 ... xn] (MATCH f x1*...xn*)
01700 A (MATCH EQ (QUOTE A))
01800 :x (POP STORE X) first time
01900 (MATCH EQUAL X) if already occurred outside OPT
02000 $x (MATCH EQUAL x)
02100 <F> (PARSE F)
02200 ::X (PARSE SHORTEST LIST) :X*
02300 →→ (ERASE THROUGH <context at beginning of rewrite>) (REC)
02400 #N (RULE_ORDER N)
02500 .A (SOURCETAIL) A*
02600
02700 When templates are merged and factored, general ALTS and Atom ALTS become:
02800
02900 a1|...|an (ALT a1 ... an)
03000 A1 a1|...|An an (DECATOMS (A1 a1) ... (An an))
03100
03200 Each function has a RANK property as follows:
03300 Rank Functions
03400
03500 0 SOURCETAIL
03600 1 BIND SOURCE MATCH EQ DECATOMS UNBIND SOURCE REC
03700 2 REQUIRE
03800 3 PARSE
03900 4 MATCH
04000 5 MATCH DECOMPOSE MATCH EQUAL
04100 6 EFFECT
04200 7 POP STORE
00100 LET FACTORER INCLUDE
00200
00300 ⊂ (PROG :V1 ::S1) (PROG :V2 ::S2) {if length(v1)>length(v2)} ⊃ →
00400 (PROG :V1 ⊂:S1 :S2⊃*)
00500 ⊂ (PROG :V1 ::S1) (PROG :V2 ::S2) ⊃ → (PROG :V2 ⊂:S1 :S2⊃*)
00600
00700 ⊂ ((MATCH EQ (QUOTE :A))...) ((MATCH EQ (QUOTE :B))...) ⊃ → (DECATOMS [FAC_ATOMS (:A ...) (:B...)])
00800 ⊂ ((MATCH EQ (QUOTE :A))...) ((DECATOMS ::BB)) ⊃ → (DECATOMS [FAC_ATOMS (:A ...) ::BB])
00900 ⊂ ((DECATOMS ::AA)) ((MATCH EQ (QUOTE :B))...) ⊃ → (DECATOMS [FAC_ATOMS (:B ...) ::AA])
01000 ⊂ ((DECATOMS ::AA)) ((DECATOMS ::BB :C)) ⊃ → ⊂ ((DECATOMS [FAC_ATOMS :C ::AA])) ((DECATOMS ::BB)) ⊃*
01100 ⊂ ((DECATOMS ::AA)) ((DECATOMS)) ⊃ → (DECATOMS ::AA)
01200
01300 ⊂ :X ((ALT ::Y)) ⊃ → (ALT [FAC_ALT :X ::Y])
01400 ⊂ ((ALT ::Y)) :X ⊃ → (ALT [FAC_ALT :X ::Y])
01500 ⊂ ((ALT ::X)) ((ALT ::Y :Z)) ⊃ → ⊂ ((ALT [FAC_ALT :Z ::X])) ((ALT ::Y)) ⊃*
01600 ⊂ ((ALT ::X)) ((ALT)) ⊃ → (ALT ::X)
01700
01800 ⊂ (:A ::AA) (:A ::BB) ⊃ → ⊂ :A ⊂:AA :BB⊃* ⊃
01900 ⊂ (:A ::AA) (:B ::BB) {if A.RANK>B.RANK}⊃ → (ALT (:A ::AA) (:B ::B))
02000 ⊂ :X :Y ⊃ → (ALT :X :Y)
02100 ;
02200
02300 LET FAC_ATOMS INCLUDE
02400
02500 ⊂ (:A ::XX) (:A ::YY) ... ⊃ → [FAC_ATOMS ( :A ⊂:XX :YY⊃@FACTORER ) ...]
02600 ⊂ (:A ::XX) (:B ::YY) ... ⊃ → ⊂ (:B ::YY) [FAC_ATOMS (:A ::XX) ...] ⊃
02700 ⊂ (:A ::XX) ⊃ → (:A ::XX)
02800 ;
02900
03000 LET FAC_ALT INCLUDE
03100 ⊂ :A :B ... ⊃ ⊂:A :B⊃@FACTORER ≡ (ALT ...) → ⊂ :B ⊂ :A ... ⊃* ⊃
03200 ⊂ :A :B ... ⊃ ⊂:A :B⊃@FACTORER ≡ :AB → ⊂ :AB ... ⊃
03300 ⊂ :A ⊃ → ⊂ :A ⊃
03400 ;
00100 LET LISP INCLUDE
00200 (BIND SOURCE (POP STRIP)) → ⊂ (TOKEN)*
00300 (INTO LIST)@LIMP ⊃
00400
00500 (UNBIND SOURCE) → ⊂
00600 (OUTOF LIST)@LIMP ⊃
00700
00800 (POP <argsfun>:M :F ::X) → (:F ::X (TOKENS :M))*
00900 (TOKEN)*
01000 (STORE :N) @LIMP ⊃
01100
01200 (MATCH ::X) → (REQUIRE (POP ::X))*
01300
01400 (PARSE ::X) → (PREFIXSOURCE (POP ::X))*
01500
01600 (REQUIRE :X) → (COND (:X) (T (FAIL)))*
01700
01800 (PREFIXSOURCE :X) → ⊂ :X* (PREFIXSOURCE)@LIMP ⊃
01900
02000 (EFFECT :E) → :E*
02100
02200 (ALT ::X) → ⊂ (ALT) @LIMP
02300 (ALT ::X) @CONTROL ⊃
02400
02500 (MATCH EQ (QUOTE :A)) → ⊂ (TOKEN EQ :A) @LIMP
02600 (TOKEN)* ⊃
02700
02800 (DECATOMS ::X) (MAKE HASH TABLE ::X)@LIMP ≡ :TAB →
02900 ⊂ (TOKEN)*
03000 (HASH INTO :TAB) @LIMP
03100 (BH :TABLE) @LIMP
03200 (INSERT HASH TABLE :TAB) @LIMP ⊃
03300
03400 (TOKENS :N) → ⊂ :N* (TOKENS)@LIMP ⊃
03500
03600 (LONGEST) → ⊂ (LONGEST)@LIMP ⊃
03700
03800 (SHORTEST) → (SHORTEST) @LIMP
03900
04000 (POP SHORTEST LIST) → (SHORTEST)*
04100
04200 (POP LONGEST <exfn>:F) → (PASS SOURCE TO :F) @LIMP
00100 Note: (POP) does nothing. Equivalent to [] in a template.
00200 (MATCH) does nothing. Equivalent to ⊂⊃.
00300 (PARSE) does nothing. Equivalent to <> (BNF's "<empty>").
00400
00500 function token() =
00600 tokener(type(source))(source) ; NOTE: lists are a special case!
00700
00800 function token(src) = tokener(type(src))(src) ;
00900
01000 function tokener(file)(src) =
01100 convert(scan(src), buffer(src)) ;
01200
01300 function tokener(string)(src) =
01400 charlop(src) ;
01500
01600 function tokener(:other)(src) = fail ;
01700
01800 function sourcetail() =
01900 source prog1 source ← nil
02000
02100 TOKEN() JUMPGE TP, L1
02200 MOVE VAL, 0(TP)
02300 MOVE TP, 1(TP)
02400 POPJ P,
02500
02600 L1 JUMPE TP, FAIL
02700
02800 LDB REG1, [POINT 12, 1, TP]
02900 PUSH P, TP
03000 PUSHJ P, @TOKENER(REG1)
03100 POPJ P,
03200
03300 TOKENER(FILE)
03400 PUSH P, -1(P)
03500 PUSHJ P, SCAN
03600 MOVE REG1, -1(P)
03700 PUSH P, OBUF(REG1)
03800 PUSHJ P, CONVERTER(VAL)
03900 SUB P, [2,,2]
04000 JRST @1(P)
04100
04200 TOKENER(STRING)
04300 MOVE REG1, -1(TP)
04400 SOSGE (REG1)
04500 POPJ SS,
04600 ILDB VAL, 1(REG1)
04700 HRLI VAL, CHARACTER
04800 SUB P, [2,,2]
04900 JRST @1(P)
00100 TYPES: 0 NIL
00200 1 LIST (but sign bit is also on)
00300 2 IDENTIFIER
00400 3 STRING
00500 etc.
00600
00700 FUNCTION LIMP(..) =
00800
00900 (INTO LIST) → ⊂ (JUMPG VAL FAIL) (PUSH P TP) (MOVE TP VAL) ⊃
01000
01100 (OUTOF LIST) → ⊂ (JUMPN TP FAIL) (MOVE TP -N P) ⊃
01200
01300 (TOKENS) → ⊂ :L (SOJL VAL :DONE) (PUSH P VAL) (TOKEN)* (EXCH VAL (P)) (JRST L) :DONE ⊃
01400
01500 (SHORTEST) → ⊂ (PUSH SS NIL) (PUSH SS NIL)
01600 (DECDP :FIRST)*
01700 (TOKEN)@LISP
01800 (PUSH P VAL) (PUSH P NIL) (PUSHJ P, @CONS)
01900 (MOVEM VAL -N(SS)) (SKIPL -1-N(SS)) (MOVEM VAL -1-N(SS))
02000
02100 :FIRST
02200 (MOVE VAL -1-N(SS))
02300
02400 (PASS SOURCE TO :F) → ⊂ (PUSH P SRCFLAG) (PUSHJ P @:F) ⊃
02500
02600
02700 Extendable functions begin with:
02800 EXCH TP, -1(P)
02900 CAIN TP, SRCFLAG
03000 EXCH TP, -1(P)
03100
03200 and end with:
03300
03400 EXCH TP, -1(P)
03500 CAIN TP, SRCFLAG
03600 MOVE TP, -1(P)
03700